package com.min.generator.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.min.common.util.GsonUtil;
import com.min.generator.config.GeneratorConfig;
import com.min.generator.constant.Const;
import com.min.generator.dao.MysqlDao;
import com.min.generator.entity.Column;
import com.min.generator.entity.Table;
import com.min.generator.entity.TemplateData;
import com.min.generator.utils.NameUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
@Slf4j
public class GeneratorService {

    @Autowired
    private MysqlDao mysqlDao;

    @Autowired
    private GeneratorConfig generatorConfig;

    @Autowired
    private IdentifierGenerator identifierGenerator;

    public List<Table> list() {
        return mysqlDao.query();
    }

    public Table queryTable(String tableName) {
        return mysqlDao.queryTable(tableName);
    }

    public List<Column> queryColumns(String tableName) {
        return mysqlDao.queryColumns(tableName);
    }

    public void makeFile(List<String> tableNames) {
        for(String tableName : tableNames){

            Table table = queryTable(tableName);
            List<Column> columns = queryColumns(tableName);

            List<Column> tablesCols = new ArrayList<>();

            for (Column column: columns) {

                if ("PRI".equalsIgnoreCase(column.getKey()) && table.getPrimaryKey() == null) {
                    table.setPrimaryKey(column);
                }

                if (generatorConfig.getIgnoreField() != null && generatorConfig.getIgnoreField().contains(column.getName())) {
                    continue;
                }

                column.setAttributeName(StrUtil.toCamelCase(column.getName()));
                column.setAttributeType(Const.fieldTypeMap.getOrDefault(column.getDataType().toLowerCase(), "unkown"));

                tablesCols.add(column);
            }

            table.setColumns(tablesCols);
            generatorToFile(table);
        }
    }

    public byte[] makeZip(List<String> tableNames) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);

        for(String tableName : tableNames){

            Table table = queryTable(tableName);
            List<Column> columns = queryColumns(tableName);

            List<Column> tablesCols = new ArrayList<>();

            for (Column column: columns) {

                if ("PRI".equalsIgnoreCase(column.getKey()) && table.getPrimaryKey() == null) {
                    table.setPrimaryKey(column);
                }

                if (generatorConfig.getIgnoreField() != null && generatorConfig.getIgnoreField().contains(column.getName())) {
                    continue;
                }

                column.setAttributeName(StrUtil.toCamelCase(column.getName()));
                column.setAttributeType(Const.fieldTypeMap.getOrDefault(column.getDataType().toLowerCase(), "unkown"));

                tablesCols.add(column);
            }
            table.setColumns(tablesCols);
            generatorToZip(table, zip);
        }

        IoUtil.close(zip);
        return outputStream.toByteArray();
    }

    public void generatorToFile(Table table) {

        //设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader" );
        Velocity.init(prop);

        final Map<String, Object> data = formatTemplateData(generatorConfig, table);
        VelocityContext context = new VelocityContext(data);

        Const.templatesMap.forEach((k, v) -> {

            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(v, "UTF-8" );
            tpl.merge(context, sw);

            String filename = generatorConfig.getFilePath(k, data.get("className").toString());
            try {

                if (filename == null) {
                    throw new FileNotFoundException("类名：" + data.get("className").toString() + "未找到对应文件路径");
                }

                if (!FileUtil.exist(filename)) {
                    FileUtil.touch(filename);
                }

                IoUtil.write(new FileOutputStream(filename),true, sw.toString().getBytes());
            } catch (FileNotFoundException e) {
                log.error("渲染模板失败，表名：" + table.getName(), e);
            }
        });
    }

    public void generatorToZip(Table table, ZipOutputStream zip) {

        //设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader" );
        Velocity.init(prop);
        final Map<String, Object> data = formatTemplateData(generatorConfig, table);
        VelocityContext context = new VelocityContext(data);

        Const.templatesMap.forEach((k, v) -> {

            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(v, "UTF-8" );
            tpl.merge(context, sw);

            String filename = generatorConfig.getZipPath(data.get("className").toString()).getOrDefault(k, null);
            try {
                zip.putNextEntry(new ZipEntry(filename));
                IoUtil.write(zip,false, sw.toString().getBytes());
            } catch (IOException e) {
                log.error("渲染模板失败，表名：" + table.getName(), e);
            }
        });
    }

    private Map<String, Object> formatTemplateData(GeneratorConfig generatorConfig, Table table) {
        Map<String, Object> data = new HashMap<>();

        data.put("author", generatorConfig.getAuthor());
        data.put("email", generatorConfig.getEmail());
        data.put("datetime", DateUtil.today());
        data.put("moduleName", generatorConfig.getModuleName());
        data.put("packageName", generatorConfig.getPackageName());
        data.put("mainPath", generatorConfig.getMainPath());

        data.put("comments", table.getComment());
        data.put("tableName", table.getName());
        data.put("primaryKey", table.getPrimaryKey().getName());
        data.put("columns", table.getColumns());
        data.put("className", NameUtils.tableNameToClassName(table.getName(), generatorConfig.getTablePrefix()));
        data.put("pathName", NameUtils.tableNameToClassName(table.getName(), generatorConfig.getTablePrefix()).toLowerCase());

        data.put("ds_id1",identifierGenerator.nextId(new Object()));
        data.put("ds_id2",identifierGenerator.nextId(new Object()));
        data.put("ds_id3",identifierGenerator.nextId(new Object()));
        data.put("ds_id4",identifierGenerator.nextId(new Object()));
        data.put("ds_id5",identifierGenerator.nextId(new Object()));
        return data;
    }

}
